package ljl.bilibili.chat.ppt;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * ApiClient类用于与Bilibili聊天PPT相关的API进行交互
 * 它提供了创建PPT、检查生成进度、获取模板列表等功能
 */
public class ApiClient {

    // 定义JSON内容类型的字符串常量
    private static final String MEDIA_TYPE_JSON = "application/json; charset=utf-8";

    // 创建一个OkHttpClient实例，配置连接池和读取超时时间
    private final static OkHttpClient client = new OkHttpClient().newBuilder()
            .connectionPool(new ConnectionPool(100, 5, TimeUnit.MINUTES))
            .readTimeout(60 * 10, TimeUnit.SECONDS)
            .build();

    // 定义错误消息的前缀
    private static final String ERROR_MESSAGE = "Unexpected code: ";

    // 存储API的基础URL
    private final String baseUrl;

    /**
     * 构造函数，初始化ApiClient实例
     *
     * @param baseUrl API的基础URL
     */
    public ApiClient(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    /**
     * 创建PPT的方法
     * 根据提供的参数构建请求体，发送POST请求，并处理响应
     *
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @param query     查询内容
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String createPPT(String appId, String timestamp, String signature, String query) throws IOException {
        // 参数校验
        validateParameters(appId, timestamp, signature, query);

        // 构建请求体
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("query", query);
        jsonObject.put("create_model", "auto");
        jsonObject.put("theme", "blue");
        jsonObject.put("business_id", "my business_id");
        jsonObject.put("is_card_note", true);

        RequestBody body = RequestBody.create(jsonObject.toString(), MediaType.get(MEDIA_TYPE_JSON));

        // 构建并发送请求
        Request request = buildPostRequest(baseUrl + "/api/aippt/create", appId, timestamp, signature, body);
        return executeRequest(request);
    }

    /**
     * 创建大纲的方法
     * 类似于createPPT，但特定于创建大纲类型的PPT
     *
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @param query     查询内容
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String createOutline(String appId, String timestamp, String signature, String query) throws IOException {
        validateParameters(appId, timestamp, signature, query);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("query", query);
        jsonObject.put("create_model", "text");
        jsonObject.put("theme", "green");
        jsonObject.put("business_id", "my business_id");
        jsonObject.put("is_card_note", false);
        jsonObject.put("is_cover_img", true);

        RequestBody body = RequestBody.create(jsonObject.toString(), MediaType.get(MEDIA_TYPE_JSON));

        Request request = buildPostRequest(baseUrl + "/api/aippt/createOutline", appId, timestamp, signature, body);
        return executeRequest(request);
    }

    /**
     * 通过SID创建PPT的方法
     * 使用SID和大纲来创建PPT
     *
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @param sid       PPT的SID
     * @param outline   PPT的大纲
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String createPptBySid(String appId, String timestamp, String signature, String sid, String outline) throws IOException {
        validateParameters(appId, timestamp, signature, sid);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("sid", sid);
        jsonObject.put("outline", outline);
        RequestBody body = RequestBody.create(jsonObject.toString(), MediaType.get(MEDIA_TYPE_JSON));

        Request request = buildPostRequest(baseUrl + "/api/aippt/createBySid", appId, timestamp, signature, body);
        return executeRequest(request);
    }

    /**
     * 通过大纲创建PPT的方法
     * 使用查询内容和大纲来创建PPT
     *
     * @param appId     应用ID
     * @param ts        时间戳
     * @param signature 签名
     * @param query     查询内容
     * @param outline   PPT的大纲
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String createPptByOutline(String appId, String ts, String signature, String query, String outline) throws IOException {
        validateParameters(appId, ts, signature, outline);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("query", query);
        jsonObject.put("outline", outline);
        jsonObject.put("create_model", "topic");
        jsonObject.put("theme", "green");
        jsonObject.put("business_id", "my business_id");
        jsonObject.put("author", "这是一个outline生成的测试");
        jsonObject.put("is_card_note", true);

        RequestBody body = RequestBody.create(jsonObject.toString(), MediaType.get(MEDIA_TYPE_JSON));

        Request request = buildPostRequest(baseUrl + "/api/aippt/createByOutline", appId, ts, signature, body);
        return executeRequest(request);
    }

    /**
     * 检查PPT生成进度的方法
     * 发送GET请求以检查PPT的生成进度
     *
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @param sid       PPT的SID
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String checkProgress(String appId, String timestamp, String signature, String sid) throws IOException {
        validateParameters(appId, timestamp, signature, sid);

        HttpUrl url = HttpUrl.parse(baseUrl).newBuilder()
                .addPathSegment("api")
                .addPathSegment("aippt")
                .addPathSegment("progress")
                .addQueryParameter("sid", sid)
                .build();

        Request request = buildGetRequest(url.toString(), appId, timestamp, signature);
        return executeRequest(request);
    }

    /**
     * 获取模板列表的方法
     * 发送GET请求以获取可用的模板列表
     *
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    public String getTemplateList(String appId, String timestamp, String signature) throws IOException {
        validateParameters(appId, timestamp, signature);

        Request request = buildGetRequest(baseUrl + "/api/aippt/themeList", appId, timestamp, signature);
        return executeRequest(request);
    }

    /**
     * 构建POST请求的方法
     * 根据提供的URL、头部信息和请求体构建一个POST请求
     *
     * @param url       请求的URL
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @param body      请求体
     * @return 构建的Request对象
     */
    private Request buildPostRequest(String url, String appId, String timestamp, String signature, RequestBody body) {
        return new Request.Builder()
                .url(url)
                .addHeader("appId", appId)
                .addHeader("timestamp", timestamp)
                .addHeader("signature", signature)
                .post(body)
                .build();
    }

    /**
     * 构建GET请求的方法
     * 根据提供的URL和头部信息构建一个GET请求
     *
     * @param url       请求的URL
     * @param appId     应用ID
     * @param timestamp 时间戳
     * @param signature 签名
     * @return 构建的Request对象
     */
    private Request buildGetRequest(String url, String appId, String timestamp, String signature) {
        return new Request.Builder()
                .url(url)
                .addHeader("appId", appId)
                .addHeader("timestamp", timestamp)
                .addHeader("signature", signature)
                .get()
                .build();
    }

    /**
     * 执行请求的方法
     * 发送请求并处理响应
     *
     * @param request 要执行的Request对象
     * @return 服务器返回的响应内容
     * @throws IOException 如果请求执行失败
     */
    private String executeRequest(Request request) throws IOException {
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                System.out.println(response.body().string());
                throw new IOException(ERROR_MESSAGE + response);
            }
            return response.body().string();
        }
    }

    /**
     * 参数校验的方法
     * 检查提供的参数是否为空或空字符串
     *
     * @param params 要校验的参数数组
     * @throws IllegalArgumentException 如果任何参数为空或空字符串
     */
    private void validateParameters(String... params) {
        for (String param : params) {
            if (param == null || param.isEmpty()) {
                throw new IllegalArgumentException("Parameter cannot be null or empty");
            }
        }
    }
}
